package com.xinxing.city.recovery.serialport;

import android.os.Handler;
import android.util.Log;


import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.xinxing.city.recovery.APPRuntime;
import com.xinxing.city.recovery.Constant;
import com.xinxing.city.recovery.DI;
import com.xinxing.city.recovery.entitys.BucketType;
import com.xinxing.city.recovery.entitys.KernelAction;
import com.xinxing.city.recovery.entitys.KernelActions;
import com.xinxing.city.recovery.interfaces.ICallBackWeight;
import com.xinxing.city.recovery.interfaces.IDeviceKernel;
import com.xinxing.city.recovery.interfaces.IDoorState;
import com.xinxing.city.recovery.interfaces.IOverFlowListener;
import com.xinxing.city.recovery.interfaces.ISerialSendReceiveData;
import com.xinxing.city.recovery.utils.SharedPreferencesUtils;
import com.xinxing.city.recovery.utils.StringUtil;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SerialSendReceiveData implements ISerialSendReceiveData {
    private static SerialPortHelper serialPortHelper;
    private boolean isOverFlow = true;
    private int overCount = 0;
    private boolean overFlow1 = false;
    private boolean overFlow2 = false;
    private boolean overFlow3 = false;
    private boolean overFlow4 = false;
    private ICallBackWeight callBackWeight;
    private IOverFlowListener overFlowListener;
    private IDoorState iDoorState;
    private Handler handler = new Handler();
    private APPRuntime appRuntime;

//    private Map<Integer, Boolean> overFlowMap;

    @Override
    public void setDoorState(IDoorState iDoorState) {
        this.iDoorState = iDoorState;
    }


    @Override
    public void start(String sPort, int iBaudRate, IDeviceKernel kernel) {
//        Map<Integer, BucketType> bOver = new HashMap<>();
//        List<BucketType> buckets = new ArrayList<>();
//        Gson gson = new Gson();
//        String bucketStr = (String) SharedPreferencesUtils.getParam(kernel.getContent(), "bucket", "");
//        if (!bucketStr.equals("")) {
//
//            Type dev = new TypeToken<List<BucketType>>() {
//            }.getType();
//            List<BucketType> bucketTypes = gson.fromJson(bucketStr, dev);
//            for (BucketType b : bucketTypes) {
//                bOver.put(b.getNum(), b);
//            }
//        }
        Map<Integer, Long> anyWeight = new HashMap<>();
        appRuntime = DI.getInstance(APPRuntime.class);
        Log.e("TTT", "准备初始化串口  ");

        try {
            serialPortHelper = new SerialPortHelper(sPort, iBaudRate) {
                @Override
                protected void onDataReceived(byte[] buffer, int size) {
                    String res = StringUtil.byte2HexStr(buffer);
                    Log.e("Serial", res);

                    switch (buffer[2]) {
                        case (byte) 0x11://门操作
                            int roomNumber = buffer[3];
                            int roomState = buffer[4];
                            roomState(roomNumber, buffer[4]);
                            break;
                        case (byte) 0x13://称重
                            if (buffer[4] == 1) {
                                int roomNumber2 = buffer[3];
                                long weightotal = bytesToInt2(new byte[]{buffer[5], buffer[6], buffer[7], buffer[8]});
                                Log.e("wegiht", "重量为：" + weightotal);
                                long pi = appRuntime.getPiWeight().get(roomNumber2);
                                Log.e("TTT", weightotal + "   >>>1>>" + pi);

                                weightotal = weightotal - pi;
                                Log.e("TTT", weightotal + "   >>>2");
                                if (weightotal < 0) {
                                    weightotal = 0;
                                }

                                weightState(roomNumber2, weightotal);
//                                anyWeight.put(roomNumber2,weightotal);
                                appRuntime.setAnyWeight(roomNumber2, weightotal);
                                callBackWeight.setWeight(roomNumber2, weightotal);
                                callBackWeight=null;
                            } else if (buffer[4] == 2) {
                                //清零
                            }
                            break;
                        case (byte) 0x17://开门锁
                            break;
                        case (byte) 0x15://故障
                            Log.e("TTT", "故障码：" + buffer[3] + "   数据：" + buffer[4]);
                            Constant.FaultCode = buffer[3];
                            Constant.FaultData = buffer[4];
                            break;
                        case (byte) 0x14://满溢
                            if (buffer[4] == 1) {//满溢状态,数据：00未满01满溢 02压缩（仅一号位）
                                Constant.OVERRLOW.put((int) buffer[3], (int) buffer[5]);
//                                overFlowListener.overFlowState(overFlow1,overFlow2,overFlow3,overFlow4);
                                List<String> params = new ArrayList<>();
                                params.add(String.valueOf((int) buffer[3]));
                                if (buffer[5] == 1) {
                                    EventBus.getDefault().post(new KernelAction(KernelActions.OVERRLOW, params));
                                }
                                if (buffer[5] == 2) {
                                    EventBus.getDefault().post(new KernelAction(KernelActions.ZIP, params));
                                }
                            } else if (buffer[4] == 2) {//投口状态, 数据：00关门完成 01开门 02关门中
//                                if( Constant.DOOR_STATE.containsKey((int)buffer[3])){
//
//                                    int type = Constant.DOOR_STATE.get((int)buffer[3]);
//                                    Log.e("serial ","Type:  "+type+"   bu "+(int)buffer[5]);
//                                    if(type != (int)buffer[5]){
//                                        Constant.DOOR_STATE.put((int) buffer[3], (int) buffer[5]);
//                                        List<String> params = new ArrayList<>();
//                                        params.add(String.valueOf((int) buffer[3]));
//                                        EventBus.getDefault().post(new KernelAction(KernelActions.DOOR_START, params));
//                                    }
//                                }else {
                                Constant.DOOR_STATE.put((int) buffer[3], (int) buffer[5]);
                                List<String> params = new ArrayList<>();
                                params.add(String.valueOf((int) buffer[3]));
                                EventBus.getDefault().post(new KernelAction(KernelActions.DOOR_START, params));
//                                }
                            } else if (buffer[4] == 3) {//清运门状态,数据：00清运门关闭 01清运门开启
                                Constant.CLEAN_DOOR_STATE.put((int) buffer[3], (int) buffer[5]);
                                List<String> params = new ArrayList<>();
                                params.add(String.valueOf((int) buffer[3]));
                                EventBus.getDefault().post(new KernelAction(KernelActions.CLEAN_DOOR_START, params));
                            }


                            break;
                        case (byte) 0x80://关门上报
                            int roomNum = buffer[4];
                            int errorCode = buffer[3];
                            int errorCount = buffer[5];
                            if (errorCount > 5) {
                                Log.e("Serial", roomNum + "号关门次数超过5次失败,错误码：" + errorCode);
                            }
                            break;
                    }

                }
            };
            serialPortHelper.open();
        } catch (IOException e) {
            Log.e("TTTT", "E " + e.toString());
        }

    }

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            isOverFlow = true;
            overCount++;
            overflow(new IOverFlowListener() {
                @Override
                public void overFlowState(boolean num1, boolean num2, boolean num3, boolean num4) {

                }
            });
        }
    };

    @Override
    public void stop() {
        serialPortHelper.close();
    }


    public void roomState(int roomNum, byte state) {
//        iDoorState.doorState(roomNum, state);
    }

    public void weightState(int roomNum, long state) {

    }


    public static void sendtoPortBuffer(List<Byte> mBuffer) {
        byte[] bytes = new byte[mBuffer.size()];
        for (int i = 0; i < mBuffer.size(); i++) {
            bytes[i] = mBuffer.get(i);
        }
        String res = StringUtil.byte2HexStr(bytes);
        Log.e("TTT", "发送2 : " + res);
        if (!Constant.DEBUG) {
//            List<String> params8 = new ArrayList<>();
//            params8.add(res);
//            EventBus.getDefault().post(new KernelAction(KernelActions.LOG, params8));
            serialPortHelper.send(bytes);
        }

    }

    /**
     * 开门
     *
     * @param doornum
     */
    @Override
    public void openDoor(int doornum) {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x11);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x01);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }


    /**
     * 关门
     *
     * @param doornum
     */
    @Override
    public void closeDoor(int doornum) {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x11);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x00);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }


    /**
     * 查询重量
     *
     * @param doornum
     */
    @Override
    public void getWeight(int doornum, ICallBackWeight callBackWeight) {

        this.callBackWeight = callBackWeight;
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x13);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x01);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 重量清零
     *
     * @param doornum
     */
    @Override
    public void getWeightReset(int doornum) {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x13);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x02);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 重量校正1
     *
     * @param doornum
     */
    @Override
    public void getWeightCorrect1(int doornum) {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x13);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x03);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 重量校正2
     *
     * @param doornum
     */
    @Override
    public void getWeightCorrect2(int doornum) {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x13);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x04);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 开剪切
     *
     * @param doornum
     */
    @Override
    public void openCut(int doornum) {
//        appRuntime.setCut(true);
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x11);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x11);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 关剪切
     *
     * @param doornum
     */
    @Override
    public void closeCut(int doornum) {
//        appRuntime.setCut(false);
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x11);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x10);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 开压缩
     *
     * @param doornum
     */
    @Override
    public void openZip(int doornum) {
//        ArrayList<Byte> mbuffer = new ArrayList<>();
//        mbuffer.add((byte) 0x00);
//        mbuffer.add((byte) 0x07);
//        mbuffer.add((byte) 0x11);
//        mbuffer.add((byte) doornum);
//        mbuffer.add((byte) 0x06);
//        mbuffer.addAll(getCrc16(mbuffer));
//        sendtoPortBuffer(mbuffer);
    }

    /**
     * 关压缩
     *
     * @param doornum
     */
    @Override
    public void closeZip(int doornum) {
//        ArrayList<Byte> mbuffer = new ArrayList<>();
//        mbuffer.add((byte) 0x00);
//        mbuffer.add((byte) 0x07);
//        mbuffer.add((byte) 0x11);
//        mbuffer.add((byte) doornum);
//        mbuffer.add((byte) 0x07);
//        mbuffer.addAll(getCrc16(mbuffer));
//        sendtoPortBuffer(mbuffer);

    }

    /**
     * 开门锁
     *
     * @param doornum
     */
    @Override
    public void openLock(int doornum) {

        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x07);
        mbuffer.add((byte) 0x11);
        mbuffer.add((byte) doornum);
        mbuffer.add((byte) 0x02);
        mbuffer.addAll(getCrc16(mbuffer));
        sendtoPortBuffer(mbuffer);
    }

    /**
     * 满溢
     */
    @Override
    public void overflow(IOverFlowListener overFlowListener) {
//        this.overFlowListener = overFlowListener;
//        ArrayList<Byte> mbuffer = new ArrayList<>();
//        mbuffer.add((byte) 0x00);
//        mbuffer.add((byte) 0x05);
//        mbuffer.add((byte) 0x14);
//        mbuffer.addAll(getCrc16(mbuffer));
//        sendtoPortBuffer(mbuffer);
    }

    /**
     * rfid
     */
    @Override
    public void sendSingleRfid() {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0xBB);
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x22);
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x22);
        mbuffer.add((byte) 0x7E);
        sendtoPortBuffer(mbuffer);
    }

    @Override
    public void sendLoopRfid() {

    }

    /**
     * 故障上报
     */
    @Override
    public void fault() {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x05);
        mbuffer.add((byte) 0x15);
        mbuffer.add((byte) 0xB3);
        mbuffer.add((byte) 0x5F);
        sendtoPortBuffer(mbuffer);
    }

    @Override
    public void getState() {
        ArrayList<Byte> mbuffer = new ArrayList<>();
        mbuffer.add((byte) 0x00);
        mbuffer.add((byte) 0x05);
        mbuffer.add((byte) 0x15);
        mbuffer.add((byte) 0xB3);
        mbuffer.add((byte) 0x5F);
        sendtoPortBuffer(mbuffer);
    }

    static ArrayList<Byte> getCrc16(ArrayList<Byte> arr_buff) {
        int len = arr_buff.size();

        // 预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
        int crc = 0xFFFF;
        int i, j;
        for (i = 0; i < len; i++) {
            // 把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
            crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff.get(i) & 0xFF));
            for (j = 0; j < 8; j++) {
                // 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
                if ((crc & 0x0001) > 0) {
                    // 如果移出位为 1, CRC寄存器与多项式A001进行异或
                    crc = crc >> 1;
                    crc = crc ^ 0xA001;
                } else
                    // 如果移出位为 0,再次右移一位
                    crc = crc >> 1;
            }
        }
        return intToBytes2_fx(crc);
    }

    private static ArrayList<Byte> intToBytes2_fx(int value) {
        ArrayList<Byte> src = new ArrayList<Byte>();
        byte b1 = (byte) ((value >> 8) & 0xFF);
        byte b0 = (byte) (value & 0xFF);
        src.add(b0);
        src.add(b1);

        return src;
    }

    public static int bytesToInt2(byte[] bs) {

        int signedInt = ByteBuffer.wrap(bs).getInt();
        return signedInt;
    }

}
